<!--
  可复用地区选择器组件（基于 Element Plus ElCascader）
  功能：
  - 支持省→市→区县→乡镇街道 等多级异步加载
  - 使用项目现有 API：getProvinceList 与 getChildAreaList
  - v-model 双向绑定（默认返回路径 code 数组）
  - 完整的 props 类型与校验、错误处理与加载状态
  - 清晰的选中事件回调（emit: change）
-->
<template>
  <!-- ElCascader 原生支持 lazy 异步加载，这里通过 props.lazyLoad 实现 -->
  <el-cascader
    v-model="innerValue"
    :props="innerCascaderProps"
    :placeholder="placeholder"
    :disabled="disabled"
    :clearable="clearable"
    :filterable="filterable"
    @change="handleChange"
  />
  <!--
    说明：ElCascader 在 lazy=true 时会根据节点展开触发 lazyLoad，
    组件会自动显示加载中的状态，不需要额外的 loading 控制。
  -->
</template>

<script setup name="AreaCascader">
/**
 * 类型定义（JSDoc）
 * @typedef {Object} AreaItem 行政区划项
 * @property {string} code 行政区划编码
 * @property {string} name 行政区划名称
 *
 * @typedef {Object} FieldMap 字段映射
 * @property {string} valueKey 作为 value 的字段名，默认 'code'
 * @property {string} labelKey 作为 label 的字段名，默认 'name'
 */

import { ref, computed, watch } from 'vue'
import { getProvinceList, getChildAreaList } from '@/api/common'

// Props 定义：包含运行时校验
const props = defineProps({
  /** v-model 绑定值：路径代码数组（如 ['110000','110100','110101']）或单个字符串 */
  modelValue: {
    type: [Array, String],
    default: () => []
  },
  /** 禁用状态 */
  disabled: { type: Boolean, default: false },
  /** 占位文案 */
  placeholder: { type: String, default: '请选择地区' },
  /** 是否可清空 */
  clearable: { type: Boolean, default: true },
  /** 是否可搜索 */
  filterable: { type: Boolean, default: true },
  /** 字段映射：后端字段与组件字段的映射关系 */
  fieldMap: {
    type: Object,
    default: () => ({ valueKey: 'code', labelKey: 'name' }),
    validator(val) {
      // 简单的参数校验：确保必需键存在且为字符串
      return val && typeof val.valueKey === 'string' && typeof val.labelKey === 'string'
    }
  },
  /** 透传 ElCascader 原生 props，允许调用方自定义行为（将与默认配置合并） */
  cascaderProps: {
    type: Object,
    default: () => ({})
  }
})

// 事件：
// - update:modelValue：用于 v-model 双向绑定
// - change：选中事件，提供完整的路径 codes、labels 与节点数据
const emit = defineEmits(['update:modelValue', 'change'])

// 内部值：归一化为数组形式，便于与 ElCascader 交互
const innerValue = ref(Array.isArray(props.modelValue) ? props.modelValue : props.modelValue ? [props.modelValue] : [])

/**
 * 将接口返回的列表标准化为 Cascader 节点格式
 * - 避免不必要对象复制：只保留必要键，减少冗余字段
 * - 统一使用惰性加载，因此初始不指定 children
 */
function normalizeList(raw) {
  // 输入容错：当返回值不是数组时，提前返回空数组
  if (!Array.isArray(raw)) return []
  const vKey = props.fieldMap.valueKey
  const lKey = props.fieldMap.labelKey
  return raw.map(item => ({
    // value 与 label 使用映射，若缺省则尝试通用字段名
    [vKey]: item?.[vKey] ?? item?.code ?? '',
    [lKey]: item?.[lKey] ?? item?.name ?? '',
    // 使用惰性加载，初始不标记 leaf，除非后续查询为空
    leaf: item?.level === 3
  }))
}

// 默认的 Cascader 行为配置：开启懒加载 + emitPath 返回完整路径
const defaultCascaderProps = computed(() => ({
  value: props.fieldMap.valueKey,
  label: props.fieldMap.labelKey,
  emitPath: true, // 返回完整路径（数组），与页面原绑定保持一致
  lazy: true, // 开启惰性加载
  /**
   * 懒加载函数：根据节点层级加载对应数据
   * - 根节点（level===0）：加载省级行政区划
   * - 其他节点：根据父级 code 加载子级区划
   * - 错误处理：展示错误提示并返回空列表，避免阻断交互
   */
  lazyLoad: async (node, resolve) => {
    try {
      if (node.level === 0) {
        // 加载省级行政区划列表
        const res = await getProvinceList()
        const list = normalizeList(res)
        resolve(list)
      } else {
        // 根据父级 code 加载下级行政区划
        const parentCode = node.value
        const res = await getChildAreaList(parentCode)
        const children = normalizeList(res)
        // 若子级为空，标记为叶子节点，避免重复请求
        if (!children || children.length === 0) {
          node.isLeaf = true
        }
        resolve(children)
      }
    } catch (error) {
      // 必要的错误处理：用户提示 + 不中断交互
      console.error('地区数据加载失败:', error)
      resolve([])
    }
  }
}))

// 最终透传给 ElCascader 的 props：默认配置与调用方透传合并
const innerCascaderProps = computed(() => ({
  ...defaultCascaderProps.value,
  ...props.cascaderProps
}))

// 监听外部 v-model 变更，保持内部状态同步
watch(
  () => props.modelValue,
  val => {
    // 提前返回，避免多层嵌套：仅处理必要分支
    if (Array.isArray(val)) {
      innerValue.value = val
      return
    }
    if (val) {
      innerValue.value = [val]
      return
    }
    innerValue.value = []
  }
)

// 选中事件处理：抛出更清晰的回调数据结构
function handleChange(val, selectedData) {
  // val 为路径 codes（因 emitPath=true），selectedData 为各级节点对象列表
  emit('update:modelValue', val || [])
  const lKey = props.fieldMap.labelKey
  const pathLabels = Array.isArray(selectedData) ? selectedData.map(n => n?.[lKey] ?? n?.label ?? '') : []
  emit('change', {
    pathCodes: val || [],
    pathLabels,
    nodes: selectedData || []
  })
}
</script>

<style scoped>
/* 本组件不强制样式，遵循 Element Plus 默认样式 */
</style>
